package thread.knn.task;

import thread.knn.bean.BankMarketing;
import thread.knn.bean.Distance;
import thread.knn.bean.Sample;

import java.util.*;

/*
    knn任务调度类
 */
public class ParallelGroupKnnClassifier {
    private int k;//近邻几个点
    private int numThreads;//线程个数
    private List<BankMarketing> data;//训练集
    private boolean parallel;//是否并行

    public ParallelGroupKnnClassifier(int k, int numThreads, List<BankMarketing> data, boolean parallel) {
        this.k = k;
        this.numThreads = numThreads;
        this.data = data;
        this.parallel = parallel;
    }

    public String classify(Sample sample) {
        Distance[] distances = new Distance[data.size()];
        //1.计算 每个线程的计算范围
        int length = data.size() / numThreads;
        int startIndex = 0;
        int endIndex = length;
        List<Thread> list = new ArrayList<>();

        //2.根据numThreads创建任务，并绑定线程
        for (int i=0;i<numThreads;i++){
            //计算example这个样本和data中每个样本的距离
            GroupDistanceTask task = new GroupDistanceTask(distances, startIndex, endIndex, sample, data);
            Thread t = new Thread(task);
//            t.setName(i+"");
            t.start();
            list.add(t);
            //如果是最后一个线程，end为matrix1的行数
            startIndex = endIndex;
            if (i==numThreads-2)
                endIndex = data.size();
            else
                endIndex += length;
            System.out.println("start:"+startIndex+" end:"+endIndex);
//            t.interrupt();
        }
        //3.调用每个线程 join() 让主线程停止，计算时间
        for (Thread t:list){
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //4.排序距离
        if (parallel)
            Arrays.parallelSort(distances);
        else
            Arrays.sort(distances);
        //5.将前k个样本的标签存到一个Map<String,Integer>(标签名，次数)
        Map<String ,Integer> result = new HashMap<>();
        //取前k条数据
        for (int i=0;i<k;i++){
            Sample sample1 = data.get(distances[i].getIndex());
            //getTag getData
            String tag = sample1.getTag();
            //map中存过
//            if (result.containsKey(tag)){
//                result.put(tag,result.get(tag)+1);
//            }else {//第一次出现标签
//                result.put(tag,1);
//            }
            //如果有tag，次数加1，没有则添加
            result.merge(tag,1,(a,b)->a+b);//如果不存在tag，则存入tag，1；否则，存入a+b
        }
        //6.将Map中次数最大的标签作为样本的标签
        //传统写法
//        Set<Map.Entry<String ,Integer>> set = result.entrySet();
//        int max = 0;
//        String maxTag = "";
//        for (Map.Entry<String,Integer> entry:set){
//            String tag = entry.getKey();
//            int count = entry.getValue();
//            if (count > max) {
//                max = count;
//                maxTag = tag;
//            }
//            return maxTag;
//        }
        //获取次数最大的标签
        //     集合工具类
        return Collections.max(result.entrySet(),Map.Entry.comparingByValue()).getKey();
    }
}